package com.utils.info.util.hhy;

import lombok.SneakyThrows;

import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Stream;

public class DateUtil {

    private static final DateTimeFormatter mySelfFormatterTime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final DateTimeFormatter mySelfFormatterDate = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    private static final DateTimeFormatter mySelfFormatterDateM = DateTimeFormatter.ofPattern("yyyy-MM");
    private static final DateTimeFormatter mySelfFormatterDateY = DateTimeFormatter.ofPattern("yyyy");
    private static final DateTimeFormatter mySelfFormatterDateYM = DateTimeFormatter.ofPattern("yyyyMM");
    private static final DateTimeFormatter mySelfFormatterDateYMDH = DateTimeFormatter.ofPattern("yyyy-MM-dd HH");
    private static final DateTimeFormatter mySelfFormatterDateYMDHZero = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:00:00");
    private static final DateTimeFormatter mySelfFormatterDateYMDHMS = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
    private static final DateTimeFormatter mySelfFormatterDateHMS = DateTimeFormatter.ofPattern("HH:mm:ss");

    /**
     * 获取当前的时间yyyy-MM-dd HH:mm:ss
     *
     * @return 当前时间
     */
    public static String getTime() {
        LocalDateTime localDateTime = LocalDateTime.now();
        return localDateTime.format(mySelfFormatterTime);


    }

    /**
     * 获取当前的时间yyyy-MM-dd
     *
     * @return 当前日期
     */
    public static String getDate() {
        LocalDate localDate = LocalDate.now();
        return localDate.format(mySelfFormatterDate);
    }


    /**
     * 获取当前的时间yyyy-MM
     *
     * @return 当前月份
     */
    public static String getDateYAndM() {
        LocalDate localDate = LocalDate.now();
        return localDate.format(mySelfFormatterDateM);
    }

    /**
     * 获取当前的时间yyyyMM
     *
     * @return 当前月份
     */
    public static String getDateYM() {
        LocalDate localDate = LocalDate.now();
        return localDate.format(mySelfFormatterDateYM);
    }

    /**
     * 将时间字符串转成LocalDateTime
     *
     * @param time 时间
     * @return 转换后时间
     */
    public static LocalDateTime DateParse(String time) {
        return LocalDateTime.parse(time, mySelfFormatterTime);
    }

    /**
     * 将时间字符串转成LocalDate
     *
     * @param time 时间
     * @return 转换后时间
     */
    public static LocalDate DateParseToYMD(String time) {
        return LocalDate.parse(time, mySelfFormatterDate);
    }

    /**
     * 将时间字符串转换成int（YYMM）类型
     */
    public static Integer DateParseToYYMM(String time) {
        Integer yearAndMonth;
        Map map = DateUtil.getTimeMap(time);
        //获取需要查询的当前月、年、日
        int year = (int) map.get("year");
        int month = (int) map.get("month");
        String monthNum;
        if (String.valueOf(month).length() == 1) {
            monthNum = "0" + month;
        } else {
            monthNum = String.valueOf(month);
        }
        String year1 = String.valueOf(year);
        String yyMM = year1 + monthNum;
        yearAndMonth = Integer.parseInt(yyMM);
        return yearAndMonth;
    }

    /**
     * 获取LocalDateTime
     *
     * @return 当前时间
     */
    public static LocalDateTime getLocalDateTime() {
        return LocalDateTime.now();
    }

    /**
     * 获取LocalDate
     *
     * @return
     */
    public static LocalDate getLocalDate() {
        LocalDate now = LocalDate.now();
        return now;
    }

    /**
     * 将时间yyyy-MM-dd HH:mm:ss格式化成yyyy-MM-dd 返回
     *
     * @param time
     * @return
     */
    public static String formatTimeYMD(String time) {
        LocalDate localDate = LocalDate.parse(time, mySelfFormatterTime);
        String returnTime = localDate.format(mySelfFormatterDate);
        return returnTime;

    }

    /**
     * 将时间格式化成yyyy-MM返回
     *
     * @param time
     * @return
     */
    public static String formatTimeYM(String time) {
        LocalDate localDate = LocalDate.parse(time, mySelfFormatterTime);
        return localDate.format(mySelfFormatterDateM);
    }

    /**
     * 将时间格式化成yyyy返回
     *
     * @param time
     * @return
     */
    public static String formatTimeY(String time) {
        LocalDateTime localDateTime = LocalDateTime.parse(time, mySelfFormatterTime);
        return localDateTime.format(mySelfFormatterDateY);
    }

    /**
     * 获取当前年份
     *
     * @return
     */
    public static String getYear() {
        return LocalDateTime.now().format(mySelfFormatterDateY);
    }

    /**
     * 将时间格式化成yyyy-mm-dd hh返回
     *
     * @param time
     * @return
     */
    public static String formatTimeYMDH(String time) {
        LocalDateTime localDateTime = LocalDateTime.parse(time, mySelfFormatterTime);
        return localDateTime.format(mySelfFormatterDateYMDH);
    }

    /**
     * 获取时间的年月日时分秒
     */

    public static Map getTimeMap(String time) {
        Map map = new HashMap();
        LocalDateTime localDateTime = LocalDateTime.parse(time, mySelfFormatterTime);
        map.put("year", localDateTime.getYear());
        map.put("month", localDateTime.getMonthValue());
        map.put("day", localDateTime.getDayOfMonth());
        map.put("hour", localDateTime.getHour());
        map.put("min", localDateTime.getMinute());
        map.put("second", localDateTime.getSecond());
        return map;
    }

    /**
     * 转成自定义的格式
     *
     * @param time
     * @return
     */
    public static String formatTimeUserFormat(String time, String format) {
        LocalDateTime localDateTime = LocalDateTime.parse(time, mySelfFormatterTime);
        String returnTime = localDateTime.format(DateTimeFormatter.ofPattern(format));
        return returnTime;
    }

    public static String formatTimeFormat(String time) {
        LocalDate localDate = LocalDate.parse(time, mySelfFormatterDate);
        int year = localDate.getYear();
        String month = String.valueOf(localDate.getMonthValue());
        String day = String.valueOf(localDate.getDayOfMonth());
        if (month.length() < 2) {
            month = "0" + month;
        }
        if (day.length() < 2) {
            day = "0" + day;
        }
        String returnTime = year + "年" + month + "月" + day + "日";
        return returnTime;
    }

    /**
     * 将日期转成毫秒
     *
     * @param time
     * @return
     */
    public static long getMilliSecond(String time) {
        LocalDateTime localDateTime = LocalDateTime.parse(time, mySelfFormatterTime);
        Long milliSecond = localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
        return milliSecond;
    }

    /**
     * 获取当前小时的时间戳 yyyy-MM-dd HH:00:00
     *
     * @return
     */
    public static long getCurrentMilliSecond() {
        LocalDateTime localDateTime = LocalDateTime.now();
        String time = localDateTime.format(mySelfFormatterDateYMDHZero);
        Long milliSecond = getMilliSecond(time);
        return milliSecond;
    }

    /**
     * 获取增减或减少几个小时返回的小时对应的时间戳 yyyy-MM-dd HH:00:00
     *
     * @param num
     * @return
     */
    public static long getPlusMilliSecond(int num) {
        LocalDateTime localDateTime = LocalDateTime.now().plusHours(num);
        String plusTime = localDateTime.format(mySelfFormatterDateYMDHZero);
        Long milliSecond = getMilliSecond(plusTime);
        return milliSecond;
    }

    /**
     * 给某个具体的时间增加或减少几分钟 yyyy-MM-dd HH:mm:ss
     *
     * @param time
     * @param num
     * @return
     */
    public static String getPlusForSpecificTime(String time, int num) {
        LocalDateTime localDateTime = LocalDateTime.parse(time, mySelfFormatterTime);
        LocalDateTime localDateTime1 = localDateTime.plusMinutes(num);
        String plusTime = localDateTime1.format(mySelfFormatterTime);
        return plusTime;
    }


    /**
     * 给某个具体的时间增加或减少几天 yyyy-MM-dd HH:mm:ss
     *
     * @param time
     * @param num
     * @return
     */
    public static String getPlusDayForSpecificTime(String time, int num) {
        LocalDateTime localDateTime = LocalDateTime.parse(time, mySelfFormatterTime);
        LocalDateTime localDateTime1 = localDateTime.plusDays(num);
        String plusTime = localDateTime1.format(mySelfFormatterTime);
        return plusTime;
    }


    /**
     * 给某个具体的时间增加或减少几秒钟 yyyy-MM-dd HH:mm:ss
     *
     * @param time
     * @param num
     * @return
     */
    public static String getPlusSecondsForSpecificTime(String time, long num) {
        LocalDateTime localDateTime = LocalDateTime.parse(time, mySelfFormatterTime);
        LocalDateTime localDateTime1 = localDateTime.plusSeconds(num);
        String plusTime = localDateTime1.format(mySelfFormatterTime);
        return plusTime;
    }

    /**
     * 获取增减或减少几个小时返回的小时时间 yyyy-MM-dd HH:00:00(当前时间往前推)
     *
     * @param num
     * @return
     */
    public static String getPlusTime(int num) {
        LocalDateTime localDateTime = LocalDateTime.now().plusHours(num);
        String plusTime = localDateTime.format(mySelfFormatterDateYMDHZero);
        return plusTime;
    }


    /**
     * 传入【具体某天】yyyy-mm-dd，以该天零点时间为基准，
     * 获取增加（num为正）或减少（num为负）几个小时的小时时间yyyy-MM-dd HH:00:00
     *
     * @param num
     * @return
     */
    public static String getPlusTime(String time, int num) {
        LocalDateTime localDate = LocalDateTime.parse(time + " 00:00:00", mySelfFormatterTime);
        LocalDateTime localDateTime = localDate.plusHours(num);
        String plusTime = localDateTime.format(mySelfFormatterDateYMDHZero);
        return plusTime;
    }


    /**
     * 传入【具体某小时】yyyy-MM-dd HH:00:00，以该时间为基准，
     * 获取增加（num为正）或减少（num为负）几个小时的小时时间yyyy-MM-dd HH:00:00
     *
     * @param num
     * @return
     */
    public static String getPlusTimeHour(String time, int num) {
        LocalDateTime localDate = LocalDateTime.parse(time, mySelfFormatterTime);
        LocalDateTime localDateTime = localDate.plusHours(num);
        String plusTime = localDateTime.format(mySelfFormatterTime);
        return plusTime;
    }

    /**
     * 获取当前时间增加或减少几天YYYY-MM-DD
     *
     * @return
     */
    public static String getChangeTime(int num) {
        LocalDate localDate = LocalDate.now().plusDays(num);
        String time = localDate.format(mySelfFormatterDate);
        return time;
    }

    /**
     * 获取特定时间增加或减少几天YYYY-MM-DD
     *
     * @return
     */
    public static String getChangeDate(String time, int num) {
        LocalDateTime localDate = LocalDateTime.parse(time + " 00:00:00", mySelfFormatterTime);
        LocalDateTime localDateTime = localDate.plusDays(num);
        String date = localDateTime.format(mySelfFormatterDate);
        return date;
    }

    /**
     * 获取特定时间增加或减少几月YYYY-MM-DD
     *
     * @return
     */
    public static String getChangeMonthDate(String time, int num) {
        LocalDateTime localDate = LocalDateTime.parse(time + " 00:00:00", mySelfFormatterTime);
        LocalDateTime localDateTime = localDate.plusMonths(num);
        String date = localDateTime.format(mySelfFormatterDate);
        return date;
    }

    /**
     * 获取特定时间年月增加或减少几月 返回年月
     *
     * @return
     */
    public static String getChangeMonthDate1(String time, int num) {
        LocalDateTime localDate = LocalDateTime.parse(time + "-01 00:00:00", mySelfFormatterTime);
        LocalDateTime localDateTime = localDate.plusMonths(num);
        String date = localDateTime.format(mySelfFormatterDateM);
        return date;
    }

    /**
     * 获取当前月的最后一天的日期
     */
    public static String getLastDayOfMonth(String time) {
        LocalDate today = LocalDate.parse(time, mySelfFormatterDate);
        String lastDay = (today.with(TemporalAdjusters.lastDayOfMonth())).format(mySelfFormatterDate);
        return lastDay;
    }

    /**
     * 获取当前月的第一天的日期
     */
    public static String getFirstDayOfMonth(String time) {
        LocalDate today = LocalDate.parse(time, mySelfFormatterDate);
        String firstDay = (today.with(TemporalAdjusters.firstDayOfMonth())).format(mySelfFormatterDate);
        return firstDay;
    }


    /**
     * 获取当前时间增加或减少几月YYYY-MM-DD
     *
     * @return
     */
    public static String getChangeMonthTime(int num) {
        LocalDate localDate = LocalDate.now().plusMonths(num);
        String time = localDate.format(mySelfFormatterDate);
        return time;
    }

    /**
     * 获取具体的一个时间年月日增加或减少几月返回YYYY-MM-DD
     *
     * @param date
     * @param num
     * @return
     */
    public static String getChangeMonthSpecificTime(String date, int num) {
        LocalDate localDate = LocalDate.parse(date, mySelfFormatterDate).plusMonths(num);
        String time = localDate.format(mySelfFormatterDate);
        return time;
    }

    /**
     * 获取当前时间YYYY-MM月的总天数
     *
     * @return
     */
    public static int getMonthDayNum(String time) {
        LocalDate today = LocalDate.parse(time, mySelfFormatterDate);
        int numDay = today.lengthOfMonth();
        return numDay;
    }

    /**
     * 获取当前时间YYYY的总天数
     *
     * @return
     */
    public static int getYearDayNum(String time) {
        LocalDate today = LocalDate.parse(time, mySelfFormatterDate);
        int numDay = today.lengthOfYear();
        return numDay;
    }

    /**
     * 将时间戳转化成时间字符串(yyyy-MM-dd HH:mm:ss)
     *
     * @param time
     * @return
     */
    public static String getTimeFromMin(long time) {
        LocalDateTime time2 = LocalDateTime.ofEpochSecond(time / 1000, 0, ZoneOffset.ofHours(8));
        String resultTime = mySelfFormatterTime.format(time2);
        return resultTime;
    }

    /**
     * 将时间戳转化成时间字符串(yyyy-MM-dd)
     *
     * @param time
     * @return
     */
    public static String getYMDFromMin(long time) {
        LocalDateTime time2 = LocalDateTime.ofEpochSecond(time / 1000, 0, ZoneOffset.ofHours(8));
        String resultTime = mySelfFormatterDate.format(time2);
        return resultTime;
    }


    /**
     * 将yyyymmddhhmmss转成yyyy-MM-dd HH:mm:ss
     *
     * @param time 时间
     * @return 转换后时间
     */
    public static String getFormatTimeYMDHMS(String time) {
        LocalDateTime localDateTime = LocalDateTime.parse(time, mySelfFormatterDateYMDHMS);
        String returnTime = localDateTime.format(mySelfFormatterTime);
        return returnTime;
    }


    /**
     * 将yyyy-MM-dd HH:mm:ss转成yyyymmddhhmmss
     *
     * @param time
     * @return
     */
    public static String getFormatTimeForYMDHMS(String time) {
        LocalDateTime localDateTime = LocalDateTime.parse(time, mySelfFormatterTime);
        String returnTime = localDateTime.format(mySelfFormatterDateYMDHMS);
        return returnTime;
    }

    /**
     * 将yyyyMMddhhmmss转成yyyy-MM-dd
     */
    public static String getFormatTimeYMD(String time) {
        LocalDateTime localDateTime = LocalDateTime.parse(time, mySelfFormatterDateYMDHMS);
        String returnTime = localDateTime.format(mySelfFormatterDate);
        return returnTime;
    }

    /**
     * 将LocalDateTime对象转成yyyy-MM-dd HH:mm:ss格式的字符串
     */

    public static String formatLocalDateTimeYMDHMS(LocalDateTime time) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        return df.format(time);
    }

    /**
     * 计算两个时间之间的相差的时间
     *
     * @param startTime 起始时间
     * @param endTime
     * @return
     */
    public static Map getBetweenTwoTime(String startTime, String endTime) {
        Map map = new HashMap();
        LocalDateTime now = DateUtil.DateParse(startTime);
        LocalDateTime end = DateUtil.DateParse(endTime);
        Duration duration = Duration.between(now, end);
        long days = duration.toDays(); //相差的天数
        long hours = duration.toHours();//相差的小时数
        long minutes = duration.toMinutes();//相差的分钟数
        long seconds = duration.getSeconds();//相差的秒
        long millis = duration.toMillis();//相差毫秒数
        long nanos = duration.toNanos();//相差的纳秒数
        map.put("days", days);
        map.put("hours", hours);
        map.put("minutes", minutes);
        map.put("millis", millis);
        map.put("nanos", nanos);
        map.put("seconds", seconds);
        return map;
    }

    /**
     * 两个时间相差多少月
     *
     * @param startTime 开始时间
     * @param endTime
     * @return
     */
    public static int monthDiff(String startTime, String endTime) {
        LocalDate dt1 = DateUtil.DateParseToYMD(startTime + "-01");
        LocalDate dt2 = DateUtil.DateParseToYMD(endTime + "-01");
        //获取第一个时间点的月份
        int month1 = dt1.getMonthValue();
        //获取第一个时间点的年份
        int year1 = dt1.getYear();
        //获取第一个时间点的月份
        int month2 = dt2.getMonthValue();
        //获取第一个时间点的年份
        int year2 = dt2.getYear();
        //返回两个时间点的月数差
        return (year2 - year1) * 12 + (month2 - month1);
    }

    /**
     * 两个日期 yyyy-MM-dd 相差多少天
     *
     * @param startTime 开始时间
     * @param endTime
     * @return
     */
    public static Long getDifferTimeDays(String startTime, String endTime) {
        LocalDate begin = DateUtil.DateParseToYMD(startTime);
        LocalDate end = DateUtil.DateParseToYMD(endTime);
        return end.toEpochDay() - begin.toEpochDay();
    }

    /**
     * 获取两个时间之间的集合
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 集合
     */
    public static List<String> getTwoTimeList(String startTime, String endTime) {
        LocalDate start = DateParseToYMD(startTime);
        LocalDate end = DateParseToYMD(endTime);
        List<String> list = new ArrayList<>();
        Stream.iterate(start, data -> data.plusDays(1)).limit(ChronoUnit.DAYS.between(start, end) + 1).forEach(date -> list.add(date.toString()));
        return list;
    }

    /**
     * 获取两个时间之间的集合
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 集合
     */
    public static Map<String, String> getTwoTimeMap(String startTime, String endTime) {
        LocalDate start = DateParseToYMD(startTime);
        LocalDate end = DateParseToYMD(endTime);
        Map<String, String> map = new LinkedHashMap<>();
        Stream.iterate(start, data -> data.plusDays(1)).limit(ChronoUnit.DAYS.between(start, end) + 1).forEach(date -> map.put(date.toString().split("-")[2], date.toString()));
        return map;
    }

    /**
     * 获取两个时间月份之间的集合
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 集合
     */
    public static List<String> getBetweenMonth(String startTime, String endTime) {
        LocalDate start = DateParseToYMD(startTime);
        LocalDate end = DateParseToYMD(endTime);
        List<String> list = new ArrayList<>();
        Stream.iterate(start, data -> data.plusMonths(1)).limit(ChronoUnit.MONTHS.between(start, end) + 1).forEach(date -> list.add(formatTimeYM(date.toString() + " 00:00:00")));
        return list;
    }

    public static boolean isAfterAndEqualYMD(String startTime, String endTime) {
        LocalDate start = DateParseToYMD(startTime);
        LocalDate end = DateParseToYMD(endTime);
        return (start.isAfter(end) || start.isEqual(end));
    }

    /**
     * 比较时间大小
     * startTime 大于或等于endTime 返回true,否则返回false
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 结果
     */
    public static boolean isAfterAndEqual(String startTime, String endTime) {
        LocalDateTime start = DateUtil.DateParse(startTime);
        LocalDateTime end = DateUtil.DateParse(endTime);
        return (start.isAfter(end) || start.isEqual(end));
    }

    /**
     * 比较时间大小
     * startTime 在 endTime 之后 返回true,否则返回false
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 结果
     */
    public static boolean isAfter(String startTime, String endTime) {
        LocalDateTime start = DateUtil.DateParse(startTime);
        LocalDateTime end = DateUtil.DateParse(endTime);
        return (start.isAfter(end));
    }

    /**
     * 比较时间大小
     * startTime 小于或等于endTime 返回true,否则返回false
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 结果
     */
    public static boolean isBeforeAndEqual(String startTime, String endTime) {
        LocalDateTime start = DateUtil.DateParse(startTime);
        LocalDateTime end = DateUtil.DateParse(endTime);
        return (start.isBefore(end) || start.isEqual(end));
    }

    /**
     * 比较时间大小
     * startTime 在 endTime 之前 返回true,否则返回false
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 结果
     */
    public static boolean isBefore(String startTime, String endTime) {
        LocalDateTime start = DateUtil.DateParse(startTime);
        LocalDateTime end = DateUtil.DateParse(endTime);
        return (start.isBefore(end));
    }


    /**
     * 获取两个时间之间的整点时间
     *
     * @param begin      开始时间
     * @param end        结束时间
     * @param pattern    开始时间格式
     * @param outPattern 返回时间格式
     * @return 返回两个时间之间的时间
     */
    @SneakyThrows
    public static List<String> getBetweenDate(String begin, String end, String pattern, String outPattern) {
        SimpleDateFormat format = new SimpleDateFormat(pattern);
        SimpleDateFormat format2 = new SimpleDateFormat(outPattern);
        List<String> betweenList = new ArrayList<>();

        Calendar startDay = Calendar.getInstance();
        startDay.setTime(format.parse(begin));
        startDay.add(Calendar.DATE, -1);

        while (true) {
            startDay.add(Calendar.DATE, 1);
            long newDate = startDay.getTime().getTime();
            long date = format.parse(end).getTime();
            String newend = format2.format(newDate);
            betweenList.add(newend);
            if (date == newDate) {
                break;
            }
        }
        return betweenList;
    }

    /**
     * 获取时间区间的所有整点时间
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 整点时间集合
     */
    @SneakyThrows
    public static List<String> getHourList(String startTime, String endTime, String pattern, String outPattern) {
        List<String> hourList = new ArrayList<>();
        SimpleDateFormat format = new SimpleDateFormat(pattern);
        SimpleDateFormat outFormat = new SimpleDateFormat(outPattern);

        Date startTime1 = format.parse(startTime);
        Date endTime1 = format.parse(endTime);
        Calendar tempStart = Calendar.getInstance();
        tempStart.setTime(startTime1);
        while (endTime1.getTime() >= startTime1.getTime()) {
            hourList.add(outFormat.format(startTime1));
            //有多种模式可以增加或减去相应的时间
            tempStart.add(Calendar.HOUR_OF_DAY, 1);
            startTime1 = tempStart.getTime();
        }
        return hourList;
    }
}
